<template>
	<div class="layout-pd">
		<el-card shadow="hover" header="构建交互式可视化图--gojs">
			<div id="myDiagramDiv"
				style="border: 1px solid #ccc; width: 100%; height: 470px; background: rgb(232, 232, 232); position: relative; -webkit-tap-highlight-color: rgba(255, 255, 255, 0);">
				<canvas tabindex="0" width="2054" height="936"
					style="position: absolute; top: 0px; left: 0px; z-index: 2; user-select: none; touch-action: none; width: 1027px; height: 468px;"></canvas>
				<div style="position: absolute; overflow: auto; width: 1027px; height: 468px; z-index: 1;">
					<div style="position: absolute; width: 1px; height: 1px;"></div>
				</div>
			</div>
		</el-card>
	</div>
</template>

<script setup lang="ts" name="tools">
import { reactive, onMounted, onUnmounted, nextTick, toRefs } from 'vue';
import * as go from 'gojs';

const $ = go.GraphObject.make;


// 定义变量内容
const state = reactive({

});
let myDiagram = {};
const initDiagram = () => {
	// const { } = toRefs(state)
	myDiagram = $(go.Diagram, "myDiagramDiv",//为DIV.HTML元素创建一个画布
		{
			'animationManager.initialAnimationStyle': go.AnimationStyle.None,
			InitialAnimationStarting: (e) => {
				var animation = e.subject.defaultAnimation;
				animation.easing = go.Animation.EaseOutExpo;
				animation.duration = 800;
				animation.add(e.diagram, 'scale', 0.3, 1);
				animation.add(e.diagram, 'opacity', 0, 1);
			},

			// have mouse wheel events zoom in and out instead of scroll up and down
			'toolManager.mouseWheelBehavior': go.WheelMode.Zoom,
			// support double-click in background creating a new node
			'clickCreatingTool.archetypeNodeData': { text: 'new node' },
			// enable undo & redo
			'undoManager.isEnabled': true,
		}
	);

	// when the document is modified, add a "*" to the title and enable the "Save" button
	myDiagram.addDiagramListener('Modified', (e) => {
		var button = document.getElementById('SaveButton');
		if (button) button.disabled = !myDiagram.isModified;
		var idx = document.title.indexOf('*');
		if (myDiagram.isModified) {
			if (idx < 0) document.title += '*';
		} else {
			if (idx >= 0) document.title = document.title.slice(0, idx);
		}
	});

	const colors = {
		pink: '#facbcb',
		blue: '#b7d8f7',
		green: '#b9e1c8',
		yellow: '#faeb98',
		background: '#e8e8e8',
	};
	const colorsDark = {
		green: '#3fab76',
		yellow: '#f4d90a',
		blue: '#0091ff',
		pink: '#e65257',
		background: '#161616',
	};
	myDiagram.div.style.backgroundColor = colors.background;

	myDiagram.nodeTemplate = new go.Node('Auto', {
		isShadowed: true,
		shadowBlur: 0,
		shadowOffset: new go.Point(5, 5),
		shadowColor: 'black',
	})
		.bindTwoWay('location', 'loc', go.Point.parse, go.Point.stringify)
		.add(
			new go.Shape('RoundedRectangle', {
				strokeWidth: 1.5,
				fill: colors.blue,
			})
				.bind('fill', 'type', (type) => {
					if (type === 'Start') return colors.green;
					if (type === 'End') return colors.pink;
					return colors.blue;
				})
				.bind('figure', 'type', (type) => {
					if (type === 'Start' || type === 'End') return 'Circle';
					return 'RoundedRectangle';
				}),
			new go.TextBlock({
				font: 'bold small-caps 11pt helvetica, bold arial, sans-serif',
				shadowVisible: false,
				margin: 8,
				font: 'bold 14px sans-serif',
				stroke: '#333',
			}).bind('text')
		);

	// unlike the normal selection Adornment, this one includes a Button
	myDiagram.nodeTemplate.selectionAdornmentTemplate = new go.Adornment('Spot')
		.add(
			new go.Panel('Auto')
				.add(
					new go.Shape('RoundedRectangle', { fill: null, stroke: colors.pink, strokeWidth: 3 }),
					new go.Placeholder() // a Placeholder sizes itself to the selected Node
				),

			// the button to create a "next" node, at the top-right corner
			go.GraphObject.build('Button', {
				alignment: go.Spot.TopRight,
				click: addNodeAndLink, // this function is defined below
			})
				.add(
					new go.Shape('PlusLine', { width: 6, height: 6 })
				) // end button
		);

	// clicking the button inserts a new node to the right of the selected node,
	// and adds a link to that new node
	function addNodeAndLink(e, obj) {
		var adornment = obj.part;
		var diagram = e.diagram;
		diagram.startTransaction('Add State');

		// get the node data for which the user clicked the button
		var fromNode = adornment.adornedPart;
		var fromData = fromNode.data;
		// create a new "State" data object, positioned off to the right of the adorned Node
		var toData = { text: 'new' };
		var p = fromNode.location.copy();
		p.x += 200;
		toData.loc = go.Point.stringify(p); // the "loc" property is a string, not a Point object
		// add the new node data to the model
		var model = diagram.model;
		model.addNodeData(toData);

		// create a link data from the old node data to the new node data
		var linkdata = {
			from: model.getKeyForNodeData(fromData), // or just: fromData.id
			to: model.getKeyForNodeData(toData),
			text: 'transition',
		};
		// and add the link data to the model
		model.addLinkData(linkdata);

		// select the new Node
		var newnode = diagram.findNodeForData(toData);
		diagram.select(newnode);
		diagram.commitTransaction('Add State');
		// if the new node is off-screen, scroll the diagram to show the new node
		diagram.scrollToRect(newnode.actualBounds);
	}

	// replace the default Link template in the linkTemplateMap
	myDiagram.linkTemplate = new go.Link({
		// shadow options are for the label, not the link itself
		isShadowed: true,
		shadowBlur: 0,
		shadowColor: 'black',
		shadowOffset: new go.Point(2.5, 2.5),

		curve: go.Curve.Bezier,
		curviness: 40,
		adjusting: go.LinkAdjusting.Stretch,
		reshapable: true,
		relinkableFrom: true,
		relinkableTo: true,
		fromShortLength: 8,
		toShortLength: 10,
	})
		.bindTwoWay('points')
		.bind('curviness')
		.add(
			// Main shape geometry
			new go.Shape({ strokeWidth: 2, shadowVisible: false, stroke: 'black' })
				.bind('strokeDashArray', 'progress', (progress) => (progress ? [] : [5, 6]))
				.bind('opacity', 'progress', (progress) => (progress ? 1 : 0.5)),
			// Arrowheads
			new go.Shape({ fromArrow: 'circle', strokeWidth: 1.5, fill: 'white' }).bind('opacity', 'progress', (progress) => (progress ? 1 : 0.5)),
			new go.Shape({ toArrow: 'standard', stroke: null, scale: 1.5, fill: 'black' }).bind('opacity', 'progress', (progress) => (progress ? 1 : 0.5)),
			// The link label
			new go.Panel('Auto').add(
				new go.Shape('RoundedRectangle', {
					shadowVisible: true,
					fill: colors.yellow,
					strokeWidth: 0.5,
				}),
				new go.TextBlock({
					font: '9pt helvetica, arial, sans-serif',
					margin: 1,
					editable: true, // enable in-place editing
				}).bind('text')
				// editing the text automatically updates the model data
			)
		);



	load(); // load an initial diagram from some JSON text


}



//   // Show the diagram's model in JSON format that the user may edit
//   function save() {
//     document.getElementById('mySavedModel').value = myDiagram.model.toJson();
//     myDiagram.isModified = false;
//   }
let dataJson = {
	"class": "go.GraphLinksModel",
	"nodeKeyProperty": "id",
	"nodeDataArray": [
		{ "id": -1, "loc": "155 -150", "type": "Start", "text": "Start" },
		{ "id": 0, "loc": "190 15", "text": "Shopping" },
		{ "id": 1, "loc": "353 32", "text": "Browse Items" },
		{ "id": 2, "loc": "353 166", "text": "Search Items" },
		{ "id": 3, "loc": "552 12", "text": "View Item" },
		{ "id": 4, "loc": "700 -95", "text": "View Cart" },
		{ "id": 5, "loc": "660 100", "text": "Update Cart" },
		{ "id": 6, "loc": "850 20", "text": "Checkout" },
		{ "id": -2, "loc": "830 200", "type": "End", "text": "End" }
	],
	"linkDataArray": [
		{ "from": -1, "to": 0, "progress": true, "text": "Visit online store", "curviness": -10 },
		{ "from": 0, "to": 1, "progress": true, "text": "Browse" },
		{ "from": 0, "to": 2, "progress": true, "text": "Use search bar", "curviness": -70 },
		{ "from": 1, "to": 2, "progress": true, "text": "Use search bar" },
		{ "from": 2, "to": 3, "progress": true, "text": "Click item", "curviness": -70 },
		{ "from": 2, "to": 2, "progress": false, "text": "Another search", "curviness": 40 },
		{ "from": 1, "to": 3, "progress": true, "text": "Click item" },
		{ "from": 3, "to": 0, "progress": false, "text": "Not interested", "curviness": -100 },
		{ "from": 3, "to": 4, "progress": true, "text": "Add to cart" },
		{ "from": 4, "to": 0, "progress": false, "text": "More shopping", "curviness": -150 },
		{ "from": 4, "to": 5, "progress": false, "text": "Update needed", "curviness": 70 },
		{ "from": 5, "to": 4, "progress": false, "text": "Update made" },
		{ "from": 4, "to": 6, "progress": true, "text": "Proceed" },
		{ "from": 6, "to": 5, "progress": false, "text": "Update needed" },
		{ "from": 6, "to": -2, "progress": true, "text": "Purchase made" }
	]
}

function load() {
	myDiagram.model = go.Model.fromJson(dataJson);
}





onMounted(() => {
	nextTick(() => {
		initDiagram()
	})
});




</script>

<style scoped lang="scss"></style>
